/**
 * Copyright (C) 2009 Fsti Inc.
 *
 */
package com.fsti.ppmw.port.payment;

import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.rmi.RemoteException;
import java.security.NoSuchAlgorithmException;

import org.apache.commons.lang.time.StopWatch;
import org.apache.log4j.Logger;

import com.ffcs.cryto.Cryto;
import com.ffcs.upcfj.map.soapServer.APServices;
import com.ffcs.upcfj.map.soapServer.APServicesService;
import com.ffcs.upcfj.map.soapServer.APServicesServiceLocator;
import com.ffcs.upcfj.map.soapServer.AServicesReq;
import com.ffcs.upcfj.map.soapServer.AServicesResp;
import com.ffcs.upcfj.map.soapServer.OrderReq;
import com.ffcs.upcfj.map.soapServer.OrderResp;

/**
 * 支付平台服务线程
 * 
 * 
 * @author Song Qing
 *
 */
public class PaymentServiceThread implements Runnable {
	/**
	* Logger for this class
	*/
	private static final Logger logger = Logger.getLogger(PaymentServiceThread.class);

	/**
	 * 请求参数
	 */
	private final RequestParams requestParams;
	/**
	 * 配置参数
	 */
	private final ConfigParams configParams;
	/**
	 * 能力类型
	 */
	private final AbilityType abilityType;
	/**
	 * 扩展信息
	 */
	private final String expattach;

	/**
	 * 交易流水号
	 */
	private final String apTransId;
	/**
	 * 支付接口信息DAO
	 */
	private final PaymentDAO paymentDAO;

	public PaymentServiceThread(RequestParams requestParams, ConfigParams configParams, PaymentDAO paymentDAO,
			String apTransId, AbilityType abilityType, String expattach) {
		this.requestParams = requestParams;
		this.configParams = configParams;
		this.paymentDAO = paymentDAO;
		this.apTransId = apTransId;
		this.abilityType = abilityType;
		this.expattach = Cryto.encryptBase643DES(expattach, configParams.getThreeDesKey());
	}

	public void run() {
		APServicesService service = null;
		try {
			StopWatch sw = new StopWatch();
			sw.start();

			//获取服务
			service = new APServicesServiceLocator();
			APServices services = service.getAPServices(new URL(configParams.getEndpoint()));

			//生成参数对象
			ReturnValue returnValue = new ReturnValue(requestParams, paymentDAO);
			returnValue.setAbilityType(abilityType);
			String code = "";//返回代码
			String codeDesc = "";//返回代码描述
			switch (abilityType) {
			case QUERY_ORDER:
				OrderReq oReq = getOrderReq(requestParams, expattach);
				OrderResp oResp = services.order(oReq);
				oResp.setExpattach(Cryto.decryptBase643DES(oResp.getExpattach(), configParams.getThreeDesKey()));
				returnValue.setOrderResp(oResp);
				code = returnValue.getOrderResp().getResp_code();
				codeDesc = returnValue.getOrderResp().getResp_desc();
				break;
			case PAYMENT_ORDER:
				accServices(services, returnValue);
				code = returnValue.getaServicesResp().getResp_code();
				codeDesc = returnValue.getaServicesResp().getResp_desc();
				break;
			case QUERY_POINTS:
				accServices(services, returnValue);
				code = returnValue.getaServicesResp().getResp_code();
				codeDesc = returnValue.getaServicesResp().getResp_desc();
				break;
			}

			sw.stop();
			logger.info("交易流水号：" + apTransId);
			logger.info("调用支付平台服务时间：" + sw.toString());
			logger.info("支付平台返回值：" + returnValue);
			logger.info("------------------------");
			logger.info("返回代码：" + code);
			logger.info("返回代码描述：" + codeDesc);
			logger.info("------------------------");
			returnValue.storage();
		} catch (Exception ex) {
			logger.error("后台线程调用支付平台服务出错！", ex);
		} finally {
			if (service != null) {
				service = null;
			}
		}

	}

	/**
	 * 调用支付平台接口accServices方法
	 * 
	 * 
	 * @param services
	 * @param returnValue
	 * @throws NoSuchAlgorithmException
	 * @throws UnsupportedEncodingException
	 * @throws RemoteException
	 */
	private void accServices(APServices services, ReturnValue returnValue) throws NoSuchAlgorithmException,
			UnsupportedEncodingException, RemoteException {
		AServicesReq aReq = getAServicesReq(requestParams, expattach);
		AServicesResp aResp = services.accServices(aReq);
		aResp.setExpattach(Cryto.decryptBase643DES(aResp.getExpattach(), configParams.getThreeDesKey()));
		returnValue.setaServicesResp(aResp);
	}

	/**
	 * 获取OrderReq
	 * 
	 * @param requestParams
	 * @param expattach
	 * @return
	 * @throws NoSuchAlgorithmException
	 * @throws UnsupportedEncodingException 
	 */
	private OrderReq getOrderReq(RequestParams requestParams, String expattach) throws NoSuchAlgorithmException,
			UnsupportedEncodingException {
		OrderReq oReq = new OrderReq();
		oReq.setAbility_type(requestParams.getAbilityType());
		oReq.setAp_id(configParams.getApId());
		oReq.setAp_trans_id(apTransId);
		oReq.setAp_user(requestParams.getApUser());
		oReq.setArea_code(requestParams.getAreaCode());
		oReq.setExpattach(expattach);
		oReq.setPay_id(configParams.getPayId());
		oReq.setTime_stamp(requestParams.getTimeStamp());
		oReq.setAuthenticator(buildAuthenticator(oReq));
		return oReq;
	}

	/**
	 * 获取AServicesReq
	 * 
	 * @param requestParams
	 * @param expattach
	 * @return
	 * @throws NoSuchAlgorithmException
	 * @throws UnsupportedEncodingException 
	 */
	private AServicesReq getAServicesReq(RequestParams requestParams, String expattach)
			throws NoSuchAlgorithmException, UnsupportedEncodingException {
		AServicesReq aReq = new AServicesReq();
		aReq.setAp_trans_id(apTransId);
		aReq.setTime_stamp(requestParams.getTimeStamp());
		aReq.setPay_id(configParams.getPayId());
		aReq.setAp_id(configParams.getApId());
		aReq.setArea_code(requestParams.getAreaCode());
		aReq.setAp_user(requestParams.getApUser());
		aReq.setAbility_type(requestParams.getAbilityType());
		aReq.setPay_mode(configParams.getPayModes().get(requestParams.getPayorgId()));
		aReq.setPayorg_id(configParams.getPayorgIds().get(requestParams.getPayorgId()));
		aReq.setAgreement(configParams.getAgreement());
		aReq.setSp_id(configParams.getSpId());
		aReq.setService_id(configParams.getServiceId());
		aReq.setDesc(requestParams.getUserTel());
		aReq.setEnd_flag(configParams.getEndFlag());
		aReq.setAccept_id(null);
		aReq.setExpattach(expattach);
		aReq.setAuthenticator(buildAuthenticator(aReq));
		return aReq;
	}

	/**
	 * 生成认证码
	 * 
	 * @param aReq 
	 * @return 认证码
	 * @throws NoSuchAlgorithmException
	 * @throws UnsupportedEncodingException 
	 */
	private String buildAuthenticator(AServicesReq aReq) throws NoSuchAlgorithmException, UnsupportedEncodingException {
		StringBuilder info = new StringBuilder();
		info.append(aReq.getAp_trans_id()).append(aReq.getTime_stamp()).append(aReq.getPay_id());
		info.append(aReq.getAp_id()).append(aReq.getArea_code()).append(aReq.getAp_user());
		info.append(aReq.getAbility_type()).append(aReq.getPay_mode()).append(aReq.getPayorg_id());
		info.append(aReq.getAgreement()).append(aReq.getSp_id()).append(aReq.getService_id());
		info.append(aReq.getDesc()).append(aReq.getAccept_id()).append(aReq.getEnd_flag());
		logger.info("认证码原信息:" + info);
		return buildAuthenticator(info);
	}

	/**
	 * 生成认证码
	 * 
	 * @param oReq 
	 * @return 认证码
	 * @throws NoSuchAlgorithmException
	 * @throws UnsupportedEncodingException 
	 */
	private String buildAuthenticator(OrderReq oReq) throws NoSuchAlgorithmException, UnsupportedEncodingException {
		StringBuilder info = new StringBuilder();
		info.append(oReq.getAp_trans_id()).append(oReq.getTime_stamp()).append(oReq.getPay_id());
		info.append(oReq.getAp_id()).append(oReq.getArea_code()).append(oReq.getAp_user());
		info.append(oReq.getAbility_type());
		return buildAuthenticator(info);
	}

	/**
	 * 
	 * 生成认证码
	 * 
	 * @param info
	 * @return 认证码；base64(3des(sha1(除特殊信息域外其他字段相加而成)))
	 * @throws NoSuchAlgorithmException
	 * @throws UnsupportedEncodingException 
	 */
	private String buildAuthenticator(StringBuilder info) throws NoSuchAlgorithmException, UnsupportedEncodingException {
		return Cryto.generateAuthenticator(info.toString(), configParams.getThreeDesKey());
	}
}
